package com.david.scan

import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Matrix
import android.text.TextUtils
import android.util.Log
import com.google.zxing.BarcodeFormat
import com.google.zxing.BinaryBitmap
import com.google.zxing.ChecksumException
import com.google.zxing.DecodeHintType
import com.google.zxing.EncodeHintType
import com.google.zxing.FormatException
import com.google.zxing.LuminanceSource
import com.google.zxing.MultiFormatReader
import com.google.zxing.MultiFormatWriter
import com.google.zxing.NotFoundException
import com.google.zxing.RGBLuminanceSource
import com.google.zxing.WriterException
import com.google.zxing.common.BitMatrix
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.oned.Code128Reader
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import java.util.concurrent.Executors


val singleExecutorService = Executors.newSingleThreadExecutor()

/**
 * 根据内容生成二维码图片
 */
fun createQRBitmap(contents: String, imgWidth: Int = 200, imgHeight: Int = 200, resultFunc:(Bitmap)->Unit) {
    singleExecutorService.execute {
        val hashMap:HashMap<EncodeHintType?, Any?> = HashMap()

        hashMap[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L
        //定义二维码的纠错级别，为L
        hashMap[EncodeHintType.CHARACTER_SET] = "utf-8"
        //设置字符编码为utf-8
        hashMap[EncodeHintType.MARGIN] = 2
        //设置margin属性为2,也可以不设置
        var bitMatrix: BitMatrix? = null //这个类是用来描述二维码的,可以看做是个布尔类型的数组
        try {
            bitMatrix = MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, imgWidth, imgHeight, hashMap)
            //调用encode()方法,第一次参数是二维码的内容，第二个参数是生二维码的类型，第三个参数是width，第四个参数是height，最后一个参数是hints属性
        } catch (e: WriterException) {
            e.printStackTrace()
        }
        val width = bitMatrix!!.width //获取width
        val height = bitMatrix.height //获取height
        val pixels = IntArray(width * height) //创建一个新的数组,大小是width*height
        for (i in 0 until width) {
            for (j in 0 until height) {
                //通过两层循环,为二维码设置颜色
                if (bitMatrix[i, j]) {
                    pixels[i * width + j] = Color.BLACK //设置为黑色
                } else {
                    pixels[i * width + j] = Color.WHITE //设置为白色
                }
            }
        }
        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
        //调用Bitmap的createBitmap()，第一个参数是width,第二个参数是height,最后一个是config配置，可以设置成RGB_565
        bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
        //调用setPixels(),第一个参数就是上面的那个数组，偏移为0，x,y也都可为0，根据实际需求来,最后是width ,和height

        resultFunc.invoke(bitmap)
    }
}

/**
 * 解析二维码图片内容
 */
fun decodeQRBitmap(bitmap: Bitmap, resultFunc:(String)->Unit) {
    singleExecutorService.execute {
        val hashMap:HashMap<DecodeHintType?, Any?> = HashMap()
        hashMap[DecodeHintType.CHARACTER_SET] = "utf-8" //设置解码的字符，为utf-8
        val width = bitmap.width //现在是从那个bitmap中得到width和height
        val height = bitmap.height
        val pixels = IntArray(width * height) //新建数组，大小为width*height
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height) //和什么的setPixels()方法对应
        val binaryBitmap = BinaryBitmap(HybridBinarizer(RGBLuminanceSource(width, height, pixels)))
        //BinaryBitmap这个类是用于反转二维码的，HybridBinarizer这个类是zxing在对图像进行二值化算法的一个类
        try {
            val result = MultiFormatReader().decode(binaryBitmap) //调用MultiFormatReader()方法的decode()，传入参数就是上面用的反转二维码的
            resultFunc.invoke(result.toString())
            return@execute
        } catch (e: NotFoundException) {
            e.printStackTrace()
        }
        resultFunc.invoke("")
    }
}





/**
 * 生成条形码（条形码中不可以包含）
 *
 * @param contents
 * @param desiredWidth
 * @param desiredHeight
 * @return
 */
fun createBarcode(contents: String?, desiredWidth: Int, desiredHeight: Int): Bitmap? {
    if (TextUtils.isEmpty(contents)) {
        return null
    }
    val barcodeFormat = BarcodeFormat.CODE_128
    val resultBitmap = encodeAsBitmap(contents, barcodeFormat, desiredWidth, desiredHeight)
    return rotateBmp(resultBitmap, 0f)
}

fun encodeAsBitmap(
    contents: String?,
    format: BarcodeFormat?, desiredWidth: Int, desiredHeight: Int,
): Bitmap {
    val WHITE = -0x1
    val BLACK = -0x1000000
    val writer = MultiFormatWriter()
    var result: BitMatrix? = null
    try {
        val hints: MutableMap<EncodeHintType, String?> = HashMap()
        hints[EncodeHintType.CHARACTER_SET] = "utf-8"
        hints[EncodeHintType.MARGIN] = "0"
        result = writer.encode(contents, format, desiredWidth, desiredHeight, hints)
    } catch (e: WriterException) {
        // TODO Auto-generated catch block
        e.printStackTrace()
    }
    val width = result!!.width
    val height = result.height
    val pixels = IntArray(width * height)
    // All are 0, or black, by default
    for (y in 0 until height) {
        val offset = y * width
        for (x in 0 until width) {
            pixels[offset + x] = if (result[x, y]) BLACK else WHITE
        }
    }
    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
    bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
    return bitmap
}

/**
 * 旋转bitmap
 *
 * @param b
 * @param degrees
 * @return
 */
fun rotateBmp(b: Bitmap?, degrees: Float): Bitmap? {
    var b = b
    if (degrees != 0f && b != null) {
        val m = Matrix()
        m.setRotate(degrees, b.width.toFloat() / 2, b.height.toFloat() / 2)
        try {
            val b2 = Bitmap.createBitmap(b, 0, 0, b.width,
                b.height, m, true)
            if (b != b2) {
                b.recycle()
                b = b2
            }
        } catch (ex: OutOfMemoryError) {
        }
    }
    return b
}


/**
 * 解析一维码/二维码图片
 *
 * @param bitmap 解析的图片
 * @return
 */
fun parseCode(bMap: Bitmap): String? {
    //val bMap = BitmapFactory.decodeFile("你的图片路径")
    val intArray = IntArray(bMap.width * bMap.height)
    bMap.getPixels(intArray, 0, bMap.width, 0, 0, bMap.width, bMap.height)
    val source: LuminanceSource = RGBLuminanceSource(bMap.width, bMap.height, intArray)
    val bitmap = BinaryBitmap(HybridBinarizer(source))

    val code128Reader = Code128Reader()
    try {
        val result = code128Reader.decode(bitmap)
        val barcodeText: String = result.getText()
        Log.d("BarcodeText", barcodeText)
        return barcodeText
    } catch (e: NotFoundException) {
        e.printStackTrace()
    } catch (e: ChecksumException) {
        e.printStackTrace()
    } catch (e: FormatException) {
        e.printStackTrace()
    }
    return ""
}
